package it.polimi.traveldream.web.beans.employee;

import java.math.BigDecimal;


import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import it.polimi.traveldream.ejbclient.dtos.ExcursionDTO;
import it.polimi.traveldream.ejbclient.dtos.HotelDTO;
import it.polimi.traveldream.ejbclient.dtos.TransportDTO;
import it.polimi.traveldream.ejbclient.eaos.PackageCompositionServiceEAO;
import it.polimi.traveldream.utils.exceptions.NotAllDataException;
import it.polimi.traveldream.utils.exceptions.NotAvailableException;
import it.polimi.traveldream.utils.exceptions.NotCoherentException;
import it.polimi.traveldream.utils.exceptions.NotSuchProductException;
import it.polimi.traveldream.web.beans.shared.FacesContextHandler;

import javax.annotation.PostConstruct;
import javax.ejb.EJB;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.context.FacesContext;

import org.primefaces.model.DualListModel;

@ManagedBean(name="addPackage")
@ViewScoped
public class AddPackageBean {
	@EJB
	private PackageCompositionServiceEAO pService;
	private String description;
	private Date expiry;
	private BigDecimal basePrice;
	private Date startDate;
	private Date endDate;
	private int reservations;
	private DualListModel<HotelDTO> hotels;
	private DualListModel<TransportDTO> transports;
	private DualListModel<ExcursionDTO> excursions;
	private boolean submitDisabled;
	private boolean composeDisabled;
	
	public AddPackageBean() {
	}
	
	@PostConstruct
	public void init() {
		submitDisabled = false;
		composeDisabled = true;
		pService.initPredefinedComposition();
		initBaseProductList();
		reservations = 1;
	}

	public void initBaseProductList() {
		hotels = new DualListModel<HotelDTO>(new ArrayList<HotelDTO>(), new ArrayList<HotelDTO>());
		transports = new DualListModel<TransportDTO>(new ArrayList<TransportDTO>(), new ArrayList<TransportDTO>());
		excursions = new DualListModel<ExcursionDTO>(new ArrayList<ExcursionDTO>(), new ArrayList<ExcursionDTO>());
	}
	
	public String getDescription() {
		return description;
	}

	public void setDescription(String description) {
		this.description = description;
	}

	public Date getExpiry() {
		return expiry;
	}

	public void setExpiry(Date expiry) {
		this.expiry = expiry;
	}

	public BigDecimal getBasePrice() {
		return basePrice;
	}

	public void setBasePrice(BigDecimal basePrice) {
		this.basePrice = basePrice;
	}

	public Date getStartDate() {
		return startDate;
	}

	public void setStartDate(Date startDate) {
		this.startDate = startDate;
	}

	public Date getEndDate() {
		return endDate;
	}

	public void setEndDate(Date endDate) {
		this.endDate = endDate;
	}

	public int getReservations() {
		return reservations;
	}

	public void setReservations(int reservations) {
		this.reservations = reservations;
	}
	
	public DualListModel<HotelDTO> getHotels() {
		return hotels;
	}

	public void setHotels(DualListModel<HotelDTO> hotels) {
		this.hotels = hotels;
	}

	public DualListModel<TransportDTO> getTransports() {
		return transports;
	}

	public void setTransports(DualListModel<TransportDTO> transports) {
		this.transports = transports;
	}

	public DualListModel<ExcursionDTO> getExcursions() {
		return excursions;
	}

	public void setExcursions(DualListModel<ExcursionDTO> excursions) {
		this.excursions = excursions;
	}
	
	public boolean isSubmitDisabled() {
		return submitDisabled;
	}

	public void setSubmitDisabled(boolean submitDisabled) {
		this.submitDisabled = submitDisabled;
	}

	public boolean isComposeDisabled() {
		return composeDisabled;
	}

	public void setComposeDisabled(boolean composeDisabled) {
		this.composeDisabled = composeDisabled;
	}

	private void initHotelsList() throws NotAllDataException {
		List<HotelDTO> hotelsSource =  pService.getHotels();
		hotels.setSource(hotelsSource);
		hotels.setTarget(new ArrayList<HotelDTO>());
	}
	
	private void initTransportsList() throws NotAllDataException {
		List<TransportDTO> transportsSource =  pService.getTransports();
		transports.setSource(transportsSource);
		transports.setTarget(new ArrayList<TransportDTO>());
	}
	
	private void initExcursionsList() throws NotAllDataException {
		List<ExcursionDTO> excursionSource =  pService.getExcursions();
		excursions.setSource(excursionSource);
		excursions.setTarget(new ArrayList<ExcursionDTO>());
	}
	
	public void sendBaseData() {
		try {
			pService.setBaseData(startDate, endDate, reservations);
			initHotelsList();
			initTransportsList();
			initExcursionsList();
			submitDisabled = true;
			composeDisabled = false;
			FacesContextHandler.produceFacesMessage(null,FacesContext.getCurrentInstance(),
					FacesMessage.SEVERITY_INFO, "The list of base products has been obtained. Please continue below with the package composition.");
		} catch (NotCoherentException e) {
			FacesContextHandler.produceFacesMessage(null,FacesContext.getCurrentInstance(),
					FacesMessage.SEVERITY_ERROR, "Please insert coherent dates.");
		} catch (NotAllDataException e) {
			FacesContextHandler.produceFacesMessage(null,FacesContext.getCurrentInstance(),
					FacesMessage.SEVERITY_WARN, "Please insert all correct data.");
		}
	}
	
	private void sendBaseProducts() {
		for(HotelDTO hotel : hotels.getTarget()) {
			pService.putProduct(hotel);
		}
		for(TransportDTO transport : transports.getTarget()) {
			pService.putProduct(transport);
		}
		for(ExcursionDTO excursion : excursions.getTarget()) {
			pService.putProduct(excursion);
		}
	}
	
	public String composePackage() {
		composeDisabled = true;
		if(!hotels.getTarget().isEmpty() || !transports.getTarget().isEmpty() || !excursions.getTarget().isEmpty()) {
			sendBaseProducts();
			try {
				pService.setDescription(description);
				int id = pService.composePredefinedPackage(expiry, basePrice);
				FacesContextHandler.produceFacesMessage(null,FacesContext.getCurrentInstance(),
						FacesMessage.SEVERITY_INFO, "The id of the new travel package is " + id + ".");
				return "addPackage";
			} catch (NotAvailableException e) {
				FacesContextHandler.produceFacesMessage(null,FacesContext.getCurrentInstance(),
						FacesMessage.SEVERITY_ERROR, "An inserted product is no more available. Click on the reset button and recompile the module.");
				return "addPackage";
			} catch (NotCoherentException e) {
				FacesContextHandler.produceFacesMessage(null,FacesContext.getCurrentInstance(),
						FacesMessage.SEVERITY_ERROR, "The travel package is not coherent. Please check all data. Click on the reset button and recompile the module.");
				return "addPackage";
			} catch (NotAllDataException e) {
				FacesContextHandler.produceFacesMessage(null,FacesContext.getCurrentInstance(),
						FacesMessage.SEVERITY_WARN, "Please insert all data. Click on the reset button and recompile the module.");
				return "addPackage";
			} catch (NotSuchProductException e) {
				FacesContextHandler.produceFacesMessage(null,FacesContext.getCurrentInstance(),
						FacesMessage.SEVERITY_ERROR, "An inserted product is no more available. Click on the reset button and recompile the module.");
				return "addPackage";
			}
		} else {
			FacesContextHandler.produceFacesMessage(null,FacesContext.getCurrentInstance(),
					FacesMessage.SEVERITY_WARN, "Please insert at least a product. Click on the reset button and recompile the module.");
			return "addPackage";
		}
	}
	
}
